# -*- coding: utf-8 -*-

import hashlib
import os, time, shutil, getpass
import urllib, urllib2, json
import mimetypes, mimetools, itertools, urlparse
from BeautifulSoup import BeautifulSoup

def http_headers(**headers):
    """
    Rename headers from "user_agent" like notation to traditional User-Agent one
    """
    return dict((('-'.join(map(str.capitalize,i.split('_'))),j) for i,j in headers.items()))

def mkdir_p(path):
    """
    Works like GNU mkdir -p
    """
    path = os.path.split(path)
    if path[0] != os.path.split(path[0])[0]:
        mkdir_p(path[0])
    os.chdir(path[0])
    if not os.path.isdir(path[1]):
        if os.path.exists(path[1]):
            os.remove(path[1])
        os.mkdir(path[1])

def get_static_auth():
    """
    Get authorization data from ~/.config/vk
    """
    config_dir  = os.path.join(os.getenv('HOME'), '.config')
    config_file = os.path.join(config_dir, 'vk')
    try:
        data = json.load(open(config_file))
        return data['login'], data['password']
    except IOError as e:
        res = {}
        print 'No persistent login password yet, creating:'
        res['login'] = raw_input('Login: ')
        passw = ''
        conf  = None
        while passw != conf:
            passw = getpass.getpass('Password: ')
            conf  = getpass.getpass('Confirm password: ')
        a = Vkontakte(res['login'], passw)
        if not a.cookie:
            print '\nWrong login/password, repeat'
            return get_static_auth()
        res['password'] = passw
        json.dump(res, open(config_file, 'w'))
        return get_static_auth()


class MultiPartForm(object):
    """Accumulate the data to be used when posting a form."""

    def __init__(self):
        self.form_fields = []
        self.files = []
        self.boundary = mimetools.choose_boundary()
        return

    def get_content_type(self):
        return 'multipart/form-data; boundary=%s' % self.boundary

    def add_file(self, fieldname, filename, fileHandle = None, mimetype=None):
        """Add a file to be uploaded."""
        if fileHandle is None:
            fileHandle = open(filename)
        body = fileHandle.read()
        if mimetype is None:
            mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
        self.files.append((fieldname, filename, mimetype, body))
        return

    def __str__(self):
        """Return a string representing the form data, including attached files."""
        # Build a list of lists, each containing "lines" of the
        # request.  Each part is separated by a boundary string.
        # Once the list is built, return a string where each
        # line is separated by '\r\n'.
        parts = []
        part_boundary = '--' + self.boundary

        # Add the form fields
        parts.extend(
            [ part_boundary,
              'Content-Disposition: form-data; name="%s"' % name,
              '',
              value,
            ]
            for name, value in self.form_fields.items()
            )

        # Add the files to upload
        parts.extend(
            [ part_boundary,
              'Content-Disposition: file; name="%s"; filename="%s"' % \
                 (field_name, filename),
              'Content-Type: %s' % content_type,
              '',
              body,
            ]
            for field_name, filename, content_type, body in self.files
            )

        # Flatten the list and add closing boundary marker,
        # then return CR+LF separated data
        flattened = list(itertools.chain(*parts))
        flattened.append('--' + self.boundary + '--')
        flattened.append('')
        return '\r\n'.join(flattened)



class Vkontakte(object):

    def __init__(self, login, password):
        self.login    = login
        self.password = password

    @property
    def s_value(self):
        host = 'http://login.vk.com/?act=login'
        post = urllib.urlencode({'email'  : self.login,
                                 'expire' : '',
                                 'pass'   : self.password,
                                 'vk'     : ''})

        headers = http_headers(
            user_agent    = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13 (.NET CLR 3.5.30729)',
            host          = 'login.vk.com',
            referer       = 'http://vkontakte.ru/index.php',
            connection    = 'close',
            pragma        = 'no-cache',
            cache_control = 'no-cache',
            )

        conn = urllib2.Request(host, post, headers)
        dom  = BeautifulSoup(urllib2.urlopen(conn).read())
        data = dom.findAll('input', dict(name='s'))
        return data and data[0].get('value')

    @property
    def cookie(self):
        self.cache_dir = os.path.join(os.getenv('HOME'),'.cache', 'vkontakte')
        mkdir_p(self.cache_dir)
        self.max_age   = '604800'
        filename       = hashlib.md5(self.login).hexdigest()
        filepath       = os.path.join(self.cache_dir, filename)

        if os.path.exists(filepath):
            if int(time.time()) - os.path.getmtime(filepath) < self.max_age:
                return json.load(file(filepath)).get('remixsid')

        host = 'http://vkontakte.ru/login.php?op=slogin'
        post = urllib.urlencode(dict(s = self.s_value))
        headers = http_headers(
            user_agent    = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13',
            host          = 'vkontakte.ru',
            referer       = 'http://login.vk.com/?act=login',
            connection    = 'close',
            cookie        = 'remixchk=5; remixsid=nonenone',
            pragma        = 'no-cache',
            cache_control = 'no-cache'
            )
        conn       = urllib2.Request(host, post, headers)
        data       = urllib2.urlopen(conn)
        cookie_src = data.info().get('Set-Cookie')
        self.cookies = dict([i.strip().split('=') for i in cookie_src.split(';')])

        try:
            json.dump(self.cookies,file(filepath,'w'))
        except IOError as e:
            print 'Error writing cookies to the cache: ', e

        return self.cookies.get('remixsid')

    @property
    def main_page(self):
        host = 'http://vkontakte.ru'
        headers = http_headers(
            user_agent   = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13',
            host         = 'vkontakte.ru',
            content_type = 'application/x-www-form-urlencoded; charset=UTF-8',
            connection   = 'close',
            cookie       = 'remixlang=0; remixchk=5; audio_vol=100; remixsid=%s' % self.cookie,
            )
        conn = urllib2.Request(host, None, headers)
        return urllib2.urlopen(conn).read()

    def _activityhash(self):
        dom = BeautifulSoup(self.main_page)
        activityhash = dom.findAll('input', dict(id = 'activityhash'))[0]['value']
        return activityhash

    @property
    def activity(self):
        dom = BeautifulSoup(self.main_page)
        activity = dom.findAll('a', dict(id = 'activity_text'))[0].contents[0]
        return activity

    @activity.setter
    def activity(self, setactivity):
        host = 'http://vkontakte.ru/profile.php'
        headers = http_headers(
            user_agent       = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13',
            host             = 'vkontakte.ru',
            referer          = 'http://vkontakte.ru/index.php',
            content_type     = 'application/x-www-form-urlencoded; charset=UTF-8',
            x_requested_with = 'XMLHttpRequest',
            connection       = 'close',
            cookie           = 'remixlang=0; remixchk=5; audio_vol=100; remixsid=%s' % self.cookie,
            pragma           = 'no-cache',
            cache_control    = 'no-cache'
            )

        post = urllib.urlencode(dict(activityhash = self._activityhash(),
                                     setactivity = setactivity))
        conn = urllib2.Request(host, post, headers)
        return urllib2.urlopen(conn).read()

    def picture_upload_data(self, aid, oid):
        host = 'http://vkontakte.ru/photos.php?act=add&id={aid}&oid={oid}'.format(aid = aid, oid=oid)
        headers = http_headers(
            user_agent   = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13',
            host         = 'vkontakte.ru',
            content_type = 'application/x-www-form-urlencoded; charset=UTF-8',
            connection   = 'close',
            cookie       = 'remixlang=0; remixchk=5; audio_vol=100; remixsid=%s' % self.cookie,
            )
        conn = urllib2.Request(host, None, headers)
        dom  = BeautifulSoup(urllib2.urlopen(conn).read())
        form = dom.findAll('form', {'id': 'upload'})[0]
        class A:
            url = form.get('action')
            variables = dict([ (str(i['id']), str(i['value'])) for i in form.findAll('input', type='hidden')])
        return A

    def picture_upload_file(self, upload_data, filename):
        form = MultiPartForm()
        form.form_fields = upload_data.variables
        form.add_file('file1', filename)
        body = str(form)
        headers = http_headers(
            user_agent       = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13',
            host             = 'vkontakte.ru',
            content_type     = form.get_content_type(),
            content_length   = str(len(body)),
            x_requested_with = 'XMLHttpRequest',
            connection       = 'close',
            cookie           = 'remixlang=0; remixchk=5; audio_vol=100; remixsid=%s' % self.cookie,
            pragma           = 'no-cache',
            cache_control    = 'no-cache'
            )
        conn = urllib2.Request(upload_data.url, body, headers)
        return urllib2.urlopen(conn).read()

    def picture_upload_approve(self, aid, approve):
        """
        It seems this action doesn't need anymore. But
        """
        host = 'http://vkontakte.ru/photos.php?act=editphotos&id=%aid&u=1' % aid
        dom = BeautifulSoup(approve).findAll('form', id='editPhotos')[0]
        variables = dict([ (str(i['id']), str(i['value'])) for i in dom.findAll('input', type='hidden')])
        headers = http_headers(
            user_agent       = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13',
            host             = 'vkontakte.ru',
            referer          = 'http://vkontakte.ru/index.php',
            content_type     = 'application/x-www-form-urlencoded; charset=UTF-8',
            x_requested_with = 'XMLHttpRequest',
            connection       = 'close',
            cookie           = 'remixlang=0; remixchk=5; audio_vol=100; remixsid=%s' % self.cookie,
            pragma           = 'no-cache',
            cache_control    = 'no-cache'
            )
        post = urllib.urlencode(variables)
        conn = urllib2.Request(host, post, headers)
        return urllib2.urlopen(conn).read()


